package com.cman777.springc.common.helper;

import javax.validation.constraints.NotNull;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;

/**
 * @Author: chenzhicong
 * @Date: 2019/11/8 22:19
 * @Version 1.0
 */
public final class DateUtil {
    private static final ZoneId CHINA_ZONE_ID = ZoneId.of("Asia/Shanghai");
    public static final DateTimeFormatter DATE_TIME_FORMATTER_1;
    public static final DateTimeFormatter DATE_TIME_FORMATTER_2;
    public static final DateTimeFormatter DATE_TIME_FORMATTER_3;
    public static final DateTimeFormatter DATE_TIME_FORMATTER_4;
    public static final DateTimeFormatter DATE_TIME_FORMATTER_5;
    public static final DateTimeFormatter DATE_TIME_FORMATTER_6;
    public static final DateTimeFormatter DATE_TIME_FORMATTER_7;
    public static final DateTimeFormatter DATE_TIME_FORMATTER_8;
    public static final DateTimeFormatter DATE_TIME_FORMATTER_9;
    public static final DateTimeFormatter DATE_TIME_FORMATTER_10;
    public static final DateTimeFormatter DATE_TIME_FORMATTER_11;
    public static final DateTimeFormatter DATE_TIME_FORMATTER_12;
    public static final DateTimeFormatter DATE_TIME_FORMATTER_13;
    public static final DateTimeFormatter DATE_TIME_FORMATTER_14;
    public static final DateTimeFormatter DATE_TIME_FORMATTER_15;
    public static final DateTimeFormatter DATE_TIME_FORMATTER_16;
    public static final DateTimeFormatter DATE_TIME_FORMATTER_17;
    public static final DateTimeFormatter DATE_TIME_FORMATTER_18;
    public static final DateTimeFormatter DATE_TIME_FORMATTER_19;

    private DateUtil() {
    }

    public static LocalDateTime currentDateTime() {
        return LocalDateTime.now(CHINA_ZONE_ID);
    }

    public static LocalDate currentDate() {
        return LocalDate.now(CHINA_ZONE_ID);
    }

    public static LocalTime currentTime() {
        return LocalTime.now(CHINA_ZONE_ID);
    }

    public static Year currentYear() {
        return Year.now(CHINA_ZONE_ID);
    }

    public static MonthDay currentMonthDay() {
        return MonthDay.now(CHINA_ZONE_ID);
    }

    public static YearMonth currentYearMonth() {
        return YearMonth.now(CHINA_ZONE_ID);
    }

    public static String format(TemporalAccessor temporalAccessor, DateUtil.DateTimeFormatEnum dateTimeFormatEnum) {
        switch(dateTimeFormatEnum) {
            case DATE_TIME_FORMAT_1:
                return DATE_TIME_FORMATTER_1.format(temporalAccessor);
            case DATE_TIME_FORMAT_2:
                return DATE_TIME_FORMATTER_2.format(temporalAccessor);
            case DATE_TIME_FORMAT_3:
                return DATE_TIME_FORMATTER_3.format(temporalAccessor);
            case DATE_TIME_FORMAT_4:
                return DATE_TIME_FORMATTER_4.format(temporalAccessor);
            case DATE_TIME_FORMAT_5:
                return DATE_TIME_FORMATTER_5.format(temporalAccessor);
            case DATE_TIME_FORMAT_6:
                return DATE_TIME_FORMATTER_6.format(temporalAccessor);
            case DATE_TIME_FORMAT_7:
                return DATE_TIME_FORMATTER_7.format(temporalAccessor);
            case DATE_TIME_FORMAT_8:
                return DATE_TIME_FORMATTER_8.format(temporalAccessor);
            case DATE_TIME_FORMAT_9:
                return DATE_TIME_FORMATTER_9.format(temporalAccessor);
            case DATE_TIME_FORMAT_10:
                return DATE_TIME_FORMATTER_10.format(temporalAccessor);
            case DATE_TIME_FORMAT_11:
                return DATE_TIME_FORMATTER_11.format(temporalAccessor);
            case DATE_TIME_FORMAT_12:
                return DATE_TIME_FORMATTER_12.format(temporalAccessor);
            case DATE_TIME_FORMAT_13:
                return DATE_TIME_FORMATTER_13.format(temporalAccessor);
            case DATE_TIME_FORMAT_14:
                return DATE_TIME_FORMATTER_14.format(temporalAccessor);
            case DATE_TIME_FORMAT_15:
                return DATE_TIME_FORMATTER_15.format(temporalAccessor);
            case DATE_TIME_FORMAT_16:
                return DATE_TIME_FORMATTER_16.format(temporalAccessor);
            case DATE_TIME_FORMAT_17:
                return DATE_TIME_FORMATTER_17.format(temporalAccessor);
            case DATE_TIME_FORMAT_18:
                return DATE_TIME_FORMATTER_18.format(temporalAccessor);
            case DATE_TIME_FORMAT_19:
                return DATE_TIME_FORMATTER_19.format(temporalAccessor);
            default:
                return null;
        }
    }

    public static Temporal addDay(Temporal temporal, int days) {
        return add(temporal, (long)days, ChronoUnit.DAYS);
    }

    public static Temporal addMonth(Temporal temporal, int months) {
        return add(temporal, (long)months, ChronoUnit.MONTHS);
    }

    public static Temporal addYear(Temporal temporal, int years) {
        return add(temporal, (long)years, ChronoUnit.YEARS);
    }

    public static Temporal addHour(Temporal temporal, long hours) {
        return add(temporal, hours, ChronoUnit.HOURS);
    }

    public static Temporal addMinute(Temporal temporal, long minutes) {
        return add(temporal, minutes, ChronoUnit.MINUTES);
    }

    public static Temporal addSecond(Temporal temporal, long seconds) {
        return add(temporal, seconds, ChronoUnit.SECONDS);
    }

    public static Temporal add(Temporal temporal, long timeNumber, ChronoUnit chronoUnit) {
        if (timeNumber > 0L) {
            return temporal.plus(timeNumber, chronoUnit);
        } else {
            return timeNumber == 0L ? temporal : temporal.minus(Math.abs(timeNumber), chronoUnit);
        }
    }

    public static <T extends Comparable<T>> boolean cross(@NotNull T from1, @NotNull T to1, @NotNull T from2, @NotNull T to2, boolean containEquals) {
        if (containEquals) {
            return to1.compareTo(from2) > 0 && to2.compareTo(from1) > 0;
        } else {
            return to1.compareTo(from2) >= 0 && to2.compareTo(from1) >= 0;
        }
    }

    public static <T extends Comparable<T>> boolean judgeFromTo(@NotNull T t1, @NotNull T t2, boolean containEquals) {
        if (containEquals) {
            return t1.compareTo(t2) <= 0;
        } else {
            return t1.compareTo(t2) < 0;
        }
    }

    public static void main(String[] args) {
        System.out.println(format(currentDate(), DateUtil.DateTimeFormatEnum.DATE_TIME_FORMAT_18));
        LocalDate localDate = LocalDate.of(2012, Month.FEBRUARY, 29);
        System.out.println(addYear(localDate, 1));
    }

    static {
        DATE_TIME_FORMATTER_1 = DateTimeFormatter.ofPattern(DateUtil.DateTimeFormatEnum.DATE_TIME_FORMAT_1.getFormatString());
        DATE_TIME_FORMATTER_2 = DateTimeFormatter.ofPattern(DateUtil.DateTimeFormatEnum.DATE_TIME_FORMAT_2.getFormatString());
        DATE_TIME_FORMATTER_3 = DateTimeFormatter.ofPattern(DateUtil.DateTimeFormatEnum.DATE_TIME_FORMAT_3.getFormatString());
        DATE_TIME_FORMATTER_4 = DateTimeFormatter.ofPattern(DateUtil.DateTimeFormatEnum.DATE_TIME_FORMAT_4.getFormatString());
        DATE_TIME_FORMATTER_5 = DateTimeFormatter.ofPattern(DateUtil.DateTimeFormatEnum.DATE_TIME_FORMAT_5.getFormatString());
        DATE_TIME_FORMATTER_6 = DateTimeFormatter.ofPattern(DateUtil.DateTimeFormatEnum.DATE_TIME_FORMAT_6.getFormatString());
        DATE_TIME_FORMATTER_7 = DateTimeFormatter.ofPattern(DateUtil.DateTimeFormatEnum.DATE_TIME_FORMAT_7.getFormatString());
        DATE_TIME_FORMATTER_8 = DateTimeFormatter.ofPattern(DateUtil.DateTimeFormatEnum.DATE_TIME_FORMAT_8.getFormatString());
        DATE_TIME_FORMATTER_9 = DateTimeFormatter.ofPattern(DateUtil.DateTimeFormatEnum.DATE_TIME_FORMAT_9.getFormatString());
        DATE_TIME_FORMATTER_10 = DateTimeFormatter.ofPattern(DateUtil.DateTimeFormatEnum.DATE_TIME_FORMAT_10.getFormatString());
        DATE_TIME_FORMATTER_11 = DateTimeFormatter.ofPattern(DateUtil.DateTimeFormatEnum.DATE_TIME_FORMAT_11.getFormatString());
        DATE_TIME_FORMATTER_12 = DateTimeFormatter.ofPattern(DateUtil.DateTimeFormatEnum.DATE_TIME_FORMAT_12.getFormatString());
        DATE_TIME_FORMATTER_13 = DateTimeFormatter.ofPattern(DateUtil.DateTimeFormatEnum.DATE_TIME_FORMAT_13.getFormatString());
        DATE_TIME_FORMATTER_14 = DateTimeFormatter.ofPattern(DateUtil.DateTimeFormatEnum.DATE_TIME_FORMAT_14.getFormatString());
        DATE_TIME_FORMATTER_15 = DateTimeFormatter.ofPattern(DateUtil.DateTimeFormatEnum.DATE_TIME_FORMAT_15.getFormatString());
        DATE_TIME_FORMATTER_16 = DateTimeFormatter.ofPattern(DateUtil.DateTimeFormatEnum.DATE_TIME_FORMAT_16.getFormatString());
        DATE_TIME_FORMATTER_17 = DateTimeFormatter.ofPattern(DateUtil.DateTimeFormatEnum.DATE_TIME_FORMAT_17.getFormatString());
        DATE_TIME_FORMATTER_18 = DateTimeFormatter.ofPattern(DateUtil.DateTimeFormatEnum.DATE_TIME_FORMAT_18.getFormatString());
        DATE_TIME_FORMATTER_19 = DateTimeFormatter.ofPattern(DateUtil.DateTimeFormatEnum.DATE_TIME_FORMAT_19.getFormatString());
    }

    public  enum DateTimeFormatEnum {
        DATE_TIME_FORMAT_1("yyMMddHHmmssSSS"),
        DATE_TIME_FORMAT_2("yyMMddHHmmss"),
        DATE_TIME_FORMAT_3("yyyyMMdd"),
        DATE_TIME_FORMAT_4("yyyy-MM-dd HH:mm:ss"),
        DATE_TIME_FORMAT_5("yyyy-MM-dd"),
        DATE_TIME_FORMAT_6("HH:mm:ss"),
        DATE_TIME_FORMAT_7("yyyy/MM/dd"),
        DATE_TIME_FORMAT_8("yyyy.MM.dd"),
        DATE_TIME_FORMAT_9("yyyyMMddHHmmssSSS"),
        DATE_TIME_FORMAT_10("yyyyMMddHHmmss"),
        DATE_TIME_FORMAT_11("yyyy"),
        DATE_TIME_FORMAT_12("MMdd"),
        DATE_TIME_FORMAT_13("MM-dd"),
        DATE_TIME_FORMAT_14("MM"),
        DATE_TIME_FORMAT_15("dd"),
        DATE_TIME_FORMAT_16("yyyyMM"),
        DATE_TIME_FORMAT_17("yyyy-MM"),
        DATE_TIME_FORMAT_18("yyyy年MM月dd日"),
        DATE_TIME_FORMAT_19("HHmmss");

        private final String formatString;

        DateTimeFormatEnum(String formatString) {
            this.formatString = formatString;
        }

        public String getFormatString() {
            return this.formatString;
        }
    }
}
